﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Manoso.Data.FluentMap
{
    internal interface IMapTask
    {
        /// <summary>
        /// The adaptor to generate sql statement of a targeting db engine.
        /// </summary>
        IMapAdaptor Adaptor { get; }

        /// <summary>
        /// List hold all sql commands generated.
        /// </summary>
        IList<string> Commands { get; }

        /// <summary>
        /// List hold all sql declaration of referenced id parameters.
        /// </summary>
        IList<string> Declares { get; }

        /// <summary>
        /// Hold object values of nodes in the hierarchy map.
        /// </summary>
        IDictionary<string, dynamic> Values { get; }

        /// <summary>
        /// The function submits sql commands to be executed.
        /// </summary>
        Action<string, Action> Submit { get; set; }

        /// <summary>
        /// Check wheter a given column exists.
        /// </summary>
        Func<string, bool> HasColumn { get; set; }

        /// <summary>
        /// Read value from a column.
        /// </summary>
        Func<string, object> ReadColumn { get; set; } 

        /// <summary>
        /// Reset current IMapTask object after a set of commands has completed executing.
        /// </summary>
        void Complete();

        /// <summary>
        /// Add a command to the task.
        /// </summary>
        /// <param name="command">The command to be added.</param>
        /// <param name="type">The command type.</param>
        void AddCommand(string command, MapCommandType type);
    }

    internal class MapTask : IMapTask
    {
        private bool _hasCrud;
        private readonly StringBuilder _command = new StringBuilder();

        public IMapAdaptor Adaptor { get; set; }
        public IList<string> Commands { get; private set; }
        public IList<string> Declares { get; private set; }
        public IDictionary<string, dynamic> Values { get; private set; }

        public Action<string, Action> Submit { get; set; }
        public Func<string, bool> HasColumn { get; set; }
        public Func<string, object> ReadColumn { get; set; } 

        public MapTask()
        {
            Commands = new List<string>();
            Declares = new List<string>();
            Values = new Dictionary<string, dynamic>();
        }

        public void Complete()
        {
            _command.Clear();
            _hasCrud = false;
        }

        public void AddCommand(string command, MapCommandType type)
        {
            if (!_hasCrud)
            {
                switch (type)
                {
                    case MapCommandType.Select:
                    case MapCommandType.Insert:
                    case MapCommandType.Update:
                    case MapCommandType.Delete:
                        _hasCrud = true;
                        if (_command.Length > 0)
                            Commands.Add(_command.ToString());
                        break;
                    case MapCommandType.Declare:
                        break;
                    case MapCommandType.SelectJoin:
                        _hasCrud = true;
                        break;
                    default:
                        _command.Append(command);
                        return;
                }
            }
            if (type == MapCommandType.Delete)
                Commands.Insert(0, command);
            else
                Commands.Add(command);
        }
    }
}